#include <stdio.h>
#include <unistd.h>
#include "app_common.h"
#include "voipenginec_api.h"
#include "Net.h"
#include "DevKey.h"
#include "AudioPhone.h"
#include "Audio.h"
#include "pwd.h"
#include "DOTSdkAPI.h"
#include "DOTSdkMedia.h"
#include "DOTHejiaguhua.h"
#include "Video.h"
#include "DevWifi.h"
#include "Upgrade.h"

#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>

static char g_call = 0;
static char g_call_init = 0;
static char g_call_end = 0;
static char g_call_session = 0;
static char g_calling = 0;
static char g_awake_call = 0;
static char g_has_create_engine = 0;
static int g_account_registered = 0;
static int voipLoginSuccess = 0;
static int NetConnected = 0;
static unsigned int gs_doorBellPid = 0;
static int s_FirstFrame = 0;
static int g_call_timeout = 0;

static SignalingObserverStr signalingObserverStr_;
int DOTHejiaguhuaDeInit();
int DOTHejiaguhuaCall();

int setnonblocking(int fd)
{
	int old_option = fcntl(fd, F_GETFL);
	int new_option = old_option | O_NONBLOCK;
	fcntl(fd, F_SETFL, new_option);
	return old_option;
}
int unblock_connect(const char* ip, int port, int time)
{
	int ret = 0,i = 0;
	struct sockaddr_in address;
	bzero(&address, sizeof(address));
	address.sin_family = AF_INET;
	inet_pton(AF_INET, ip, &address.sin_addr);
	address.sin_port = htons(port);

	int sockfd = socket(PF_INET, SOCK_STREAM, 0);
	int fdopt = setnonblocking(sockfd);
	ret = connect(sockfd, (struct sockaddr*)&address, sizeof(address));
	printf(">>>>>>>>>connect ret code = %d\n", ret);
	if (ret == 0)
	{
		printf("connect with server immediately\n");
		fcntl(sockfd, F_SETFL, fdopt);   //set old optional back
		return sockfd;
	}
	//unblock mode --> connect return immediately! ret = -1 & errno=EINPROGRESS
	else if (errno != EINPROGRESS)
	{
		printf(">>>>>>>>>ret = %d\n", ret);
		printf(">>>>>>>>>unblock connect failed!\n");
		return -1;
	}
	else if (errno == EINPROGRESS)
	{
		printf(">>>>>>>>>unblock mode socket is connecting...\n");
	}

	//use select to check write event, if the socket is writable, then
	//connect is complete successfully!
	//fd_set readfds;
	fd_set writefds;
	struct timeval timeout;

	FD_ZERO(&writefds);
	FD_SET(sockfd, &writefds);

	timeout.tv_sec = 1; //timeout is 10 minutes
	timeout.tv_usec = 0;
	for ( i = 0; i < 5; i++)
	{
		ret = select(sockfd + 1, NULL, &writefds, NULL, &timeout);
		if (ret <= 0)
		{
			LOGW(">>>>>>>>>connection time out[%d]\n",ret);
			continue;
		}
	}

//	if (ret <= 0)
//	{
//		LOGW(">>>>>>>>>connection time out\n");
//		close(sockfd);
//		return -1;
//	}

	if (!FD_ISSET(sockfd, &writefds))
	{
		printf(">>>>>>>>>no events on sockfd found\n");
		close(sockfd);
		return -1;
	}

	int error = 0;
	socklen_t length = sizeof(error);
	if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
	{
		printf(">>>>>>>>>get socket option failed\n");
		close(sockfd);
		return -1;
	}

	if (error != 0)
	{
		printf(">>>>>>>>>connection failed after select with the error: %d \n", error);
		close(sockfd);
		return -1;
	}
	

	//connection successful!
	printf(">>>>>>>>>connection ready after select with the socket: %d \n", sockfd);
	fcntl(sockfd, F_SETFL, fdopt); //set old optional back
	close(sockfd);
	return sockfd;
}

int DOTHjghSetLock()
{
	PowerSetWakeLock("HJGH_LOCK");
}

int DOTHjghSetUnlock()
{
	PowerSetWakeUnLock("HJGH_LOCK");
}

void OnNetConnected()
{
	printf("====================================================");
    printf("OnNetConnected()-------已连接服务器\n");
	printf("====================================================");
	NetConnected = 1;
}

void OnNetConnectionFailed(int errorCode)
{
	printf("====================================================");
    printf("OnNetConnected()-------已断开服务器\n");
	printf("====================================================");
}

void OnUserLoginSucceed(const char*user)
{
	printf("====================================================");
    printf("OnUserLoginSucceed()-------注册成功\n");
	printf("====================================================");
    g_account_registered = 1;
    voipLoginSuccess = 1;
}

void OnUserLoginFailed(const char *user, int errorCode, const char *reason)
{
	printf("====================================================");
    printf("OnUserLoginFailed()---- 注册失败, error code:%d,reason:%s\n" ,errorCode, reason);
	printf("====================================================");
	g_account_registered = 0;
}

void OnUserLogout(const char *user)
{
    printf("====================================================");
    printf("OnUserLogout()---- 用户已注销\n");
	printf("====================================================");
}

void OnRecvCall(int session, const char *from, const char *displayname, const char *to,
                int callType)
{
    printf("====================================================");
    printf("OnRecvCall()\n");
	printf("====================================================");
}
				
void OnRecvAnswer(int session, const char *from, const char *displayname, const char *to,
                  int callType)
{
#ifdef MINI_APP
    return ;
#endif /* MINI_APP */

    printf("====================================================");
    printf("OnRecvAnswer(%s)---- 已接听\n" , to);
	printf("====================================================");
	DOTHjghSetLock();
	DOTCleanTimeout();
	if (Doorbell_video_get_HD() != 0)
		Doorbell_video_set_HD(0);
	usleep(100 * 1000);
	PhoneCleanBuf();
	PhoneStartMic();
	g_calling = 1;	
	VideoGetOpsHandle()->request_idr_frame(VIDEO_CHN_MAIN);
	s_FirstFrame = 0; //接电话时清空
}

void OnRecvRing(int session, const char *from, const char *displayname, const char *to,
                int EarlyMedia)
{
	printf("====================================================");
    printf("OnRecvRing()---- 对方已经响铃, media type:%d\n" , EarlyMedia);
	printf("====================================================");
}
				
void OnRecvHangup(int session, int errorCode, const char *reason, int callType)
{
    printf("====================================================");
    printf("OnRecvHangup()---- 呼叫被挂 errorcode:%d, reason:%s, callType:%d\n", errorCode, reason, callType);
    printf("====================================================");
    g_call_session = 0;
	g_call_end = -2;
	NetConnected = 0;
	g_calling = 0;
	g_call = 0;
	PowerSetSocSleepTime(1, 10);
	DOTHjghSetUnlock();
	PhoneStopMic();
	PhoneCleanBuf();
	if (Doorbell_video_get_HD() == 1)
		Doorbell_video_set_HD(1);
}

void OnRecvReinvite(int session, const char *from, const char *displayname, const char *to,
                    int callType)
{
    printf("OnRecvReinvite***************************** \n");
}

void OnNotifyVideoRtpPort(int port)
{
    printf("OnNotifyVideoRtpPort:%d***************************** \n", port);
}

void OnRecvDtmf(int Eventno)
{
    printf("OnRecvDtmf:%d***************************** \n", Eventno);
}

void *sdk_task()
{
    SET_THREAD_NAME("sdk_task");
    pthread_detach(pthread_self());

	int ret = 0, i = 0;	
	while(voipLoginSuccess != 1){
        usleep(50 * 1000);
    }
	printf("\n\ncallphone\n");
	

	g_call_session = CGetAvailableSessionSeq();
	char callout_number[] = "88886668888";
	ret = CCallout(g_call_session, callout_number, 21);

	printf("CCallout ret[%d]\n", ret);

	pthread_exit(0);
}

void *DOThjghThread(void*args)
{
	SET_THREAD_NAME("DOThjghThread");
	pthread_detach(pthread_self());

	char outIp[32] = "";

	while (1)
	{
		sleep(1);
		NetLiteosGetAddrInfo("www.baidu.com", outIp);
		if (strlen(outIp) > 0)
		{
			if (g_call_init == 0 && !UpgradeCheckIsRun())
			{
				sleep(5);
				DOTHejiaguhuaInit();
			}
			CSetLogPrintstatus(1);
		}		
		else
		{
			if (g_call_init == 1)
			{
				DOTHejiaguhuaDeInit();
			}
			CSetLogPrintstatus(0);
		}	

		if (g_calling)
		{
			g_call_timeout++;
			if (g_call_timeout > 40)
			{
				DOTHjghSetUnlock();
			}
		}

		if (g_awake_call == 1)
		{
			DOTHejiaguhuaCall();
			g_awake_call = 0;
		}
	}

	pthread_exit(0);
}

int DOTHejiaguhuaInit()
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

	printf("\n\n\nMobileCountryHejiaguhuaInit()\n\n");
	if (!g_call_init)
	{
		printf("\n\n\n\n\nbegin test Formal Business Process By C\n\n\n\n");
		//固话那边反映CCreateEngine只用调一次
		if (!g_has_create_engine)
		{
            if (CCreateEngine() != 0)
    	   	{
    			printf("\n\n\n[%s]:%d hjgh CreateEngine failed!\n\n", __func__, __LINE__);
    			//return -1;
    		}
    		g_has_create_engine++;
		}	

		signalingObserverStr_.OnNetConnected_ = OnNetConnected;
		signalingObserverStr_.OnNetConnectionFailed_ = OnNetConnectionFailed;
		signalingObserverStr_.OnUserLoginSucceed_ = OnUserLoginSucceed;
		signalingObserverStr_.OnUserLoginFailed_ = OnUserLoginFailed;
		signalingObserverStr_.OnUserLogout_ = OnUserLogout;
		signalingObserverStr_.OnRecvCall_ = OnRecvCall;
		signalingObserverStr_.OnRecvAnswer_ = OnRecvAnswer;
		signalingObserverStr_.OnRecvHangup_ = OnRecvHangup;
		signalingObserverStr_.OnRecvRing_ = OnRecvRing;
		signalingObserverStr_.OnRecvReinvite_ = OnRecvReinvite;
		signalingObserverStr_.OnNotifyVideoRtpPort_ = OnNotifyVideoRtpPort;
		signalingObserverStr_.OnRecvDtmf_ = OnRecvDtmf;
		CRegisterSignalingObserver(&signalingObserverStr_);
		CRegisterDtmfEventObserver();

		char sn[32] = { 0 };
		char appKey[] = "yn5ggpvbgf7zl1i1"; 
		char appSecret[] = "seofr319wv0ondps";
		char deviceId[] = "cmcc-232306-5623080000000002";
		DevGetUuid(sn);

        if (DOTGetYDProductModel() == YD_PRODUCT_MODEL_B5)
        {
            //B5
            //andlinkid:232306
    		strcpy(appKey, "yn5ggpvbgf7zl1i1");
    		strcpy(appSecret, "seofr319wv0ondps");
    		sprintf(deviceId, "cmcc-232306-%s", sn);
    		printf("\ndeviceId = %s, sn = %s\n", deviceId, sn);
    		CSetOsAndDeviceModel("ML-B5_W", "LiteOS");
        }
		else if (DOTGetYDProductModel() == YD_PRODUCT_MODEL_W5)
        {
            //W5
    		strcpy(appKey, "aytkoij2cefxtf86");
    		strcpy(appSecret, "10kxr7qlztvh5rsq");
    		sprintf(deviceId, "cmcc-232307-%s", sn);
    		printf("\nappKey = %s,deviceId = %s, sn = %s\n", appKey, deviceId, sn);
    		CSetOsAndDeviceModel("ML-W5_W", "LiteOS");
        }
        else if (DOTGetYDProductModel() == YD_PRODUCT_MODEL_B7)
        {
            //B7
    		strcpy(appKey, "z5tnpzsux43c6stz");
    		strcpy(appSecret, "9n5fd6lwg3jsig1j");
    		sprintf(deviceId, "cmcc-232353-%s", sn);
    		printf("\nappKey = %s,deviceId = %s, sn = %s\n", appKey, deviceId, sn);
    		CSetOsAndDeviceModel("ML-B7_W", "LiteOS");
        } 

		char imsNumber[20];
		int wait_account = 0;

//		unblock_connect("112.13.96.172", 8888, 10);

		usleep(50 * 1000);

		while (1)
		{
			if (GetConfigWifiQrcodeStatus())
			{
				DotSdkInit();
				DOTStartBind(4);
			}
			
			int account_return = CGetIMSAccountNumber(appKey, appSecret, deviceId, imsNumber);
			if (0 == account_return)
			{
				break;
			}
			
			wait_account++;
			if (wait_account > 3)		//wait for 3s
				break;
			usleep(1000 * 1000);
		}
		g_call_init = 1;

		pthread_t DothjghPid;
		int err = pthread_create(&DothjghPid, NULL, &DOThjghThread, NULL);
		if (err != 0) {
			LOGE("pthread_create MobileCountryThread failed!\n");
			return -1;
		}
	}
	
	return 0;
}

int DOTHejiaguhuaCall()
{
#ifdef MINI_APP
    return 0;
#endif /* MINI_APP */

	printf("\n\nMobileCountryHejiaguhuaCall\n\n");

	if (!g_call)
	{
		pthread_t test_id;
		pthread_attr_t attr;
		pthread_attr_init(&attr);
		pthread_attr_setstacksize(&attr, 1024 * 1024 * 2);
		//pthread_attr_setstacksize(&attr, 1024 * 500);
		pthread_create(&test_id, &attr, &sdk_task, NULL);
		printf("MI_task id: %d\n", test_id);
		pthread_attr_destroy(&attr);
		g_call_end = 0;
		g_call = 1;

//		pthread_join(test_id, NULL);
	}

	return 0;
}

int DOTHjghPressDoorbell(int WakeUpType)
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

	if (g_calling || g_call_init == 0)
	{
		if (!g_call_init)
		{
			//if (WakeUpType == 1 || MC_get_register_status() == 1)
			if (MC_get_register_status() == 0)
				g_awake_call = 1;
		}			
		return 0;
	}
		
	PowerSetSocSleepTime(1, 45);
	DOTHejiaguhuaCall();

	return 0;
}

int DOTHejiaguhuaDeInit()
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

	if (g_call_init)
	{
		if(1 == g_account_registered)
		{
	        	CDeregisterUserFromIMSServer();
	        	g_account_registered = 0;
	    	}
		
		CDeregisterSignalingObserver();
		//固话那边反映CDestroyEngine容易出问题，不要调
		//CDestroyEngine();
		g_call_init = 0;
		
	    	printf("\nExit Formal Business Proces\n");
	}

	return 0;
}

int DOTHjghCalling()
{
	return g_calling;	
}

void DOTSetGCall(int ncall)
{
	g_call = ncall;
}

void DOTCleanTimeout(void)
{
	g_call_timeout = 0;
}

void DOTSetHandUp(void)
{
#ifdef MINI_APP
        return ;
#endif /* MINI_APP */

	if (g_call_session)
	{
		CHangup(g_call_session);
		NetConnected = 0;
		g_call_session = 0;
		g_calling = 0;
		g_call = 0;
		DOTHjghSetUnlock();
		PhoneStopMic();
		PhoneCleanBuf();
		if (Doorbell_video_get_HD() == 1)
			Doorbell_video_set_HD(1);
	}
}

int DOTHjghSendVideoOut(int isIFrame, char* data, int length)
{
#ifdef MINI_APP
    return 0;
#endif /* MINI_APP */

#if 0
	if (s_FirstFrame || isIFrame)
	{
		s_FirstFrame = 1;//I֡
		return CSendVideoOut(g_call_session, data, length);
	}
#elif 0
	if (!s_FirstFrame && !isIFrame)
	{
		s_FirstFrame = 1;
		VideoGetOpsHandle()->request_idr_frame(VIDEO_CHN_MAIN);
	}
	if (s_FirstFrame || isIFrame)
		return CSendVideoOut(g_call_session, data, length);
#else
	return CSendVideoOut(g_call_session, data, length);
#endif
}

int DOTHjghPutAudioDateToList(void* data, unsigned int length)
{
#ifdef MINI_APP
    return 0;
#endif /* MINI_APP */

	if(1 == PhoneGetFlagMic())
	{
		unsigned char pcm[1024];
		int pcm_len = 0;
		int ret;

		g711_adec((unsigned char *)data, length, pcm, &pcm_len);
		if (pcm_len <= 0) {
			LOGE("g711_adec failed\n");
			return -1;
		}
		#if 0
		static FILE *fp = NULL;

		if (fp == NULL) {
			fp = fopen("/nfs/test.pcm", "wb");
			if (fp == NULL) {
				printf("fopen failed\n");
				return NULL;
			}
		}

		fwrite(pcm, 1, pcm_len, fp);
		sync();
		#endif		
		ret = PhonePutAudioDateToList(pcm, pcm_len);
	}	
	else
		return -1;

	return 0;
}



